package com.atguigu.exam.service.impl;

import com.atguigu.exam.entity.PaperQuestion;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.entity.QuestionAnswer;
import com.atguigu.exam.entity.QuestionChoice;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.PaperQuestionMapper;
import com.atguigu.exam.mapper.QuestionAnswerMapper;
import com.atguigu.exam.mapper.QuestionChoiceMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.BannerService;
import com.atguigu.exam.service.QuestionService;
import com.atguigu.exam.vo.QuestionQueryDto;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 题目Service实现类
 * 实现题目相关的业务逻辑
 */
@Slf4j
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {


    private final QuestionChoiceMapper questionChoiceMapper;

    @Autowired
    private QuestionAnswerMapper questionAnswerMapper;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private PaperQuestionMapper paperQuestionMapper;

    public QuestionServiceImpl(QuestionChoiceMapper questionChoiceMapper) {
        this.questionChoiceMapper = questionChoiceMapper;
    }

    @Override
    public Page<Question> getPageByCondition(Page<Question> questionPage, QuestionQueryDto questionQueryDto) {
        //调用QuestionMapper里分页查询及待条件查询的方法
       Page<Question> questionPage1 =  baseMapper.getPageByCondition(questionPage,questionQueryDto);
        return questionPage1;
    }

    @Transactional
    @Override
    public void createQuestion(Question question) {
        //判断当前题目类型中是否已存在该题目
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Question>().eq(Question::getTitle, question.getTitle()).eq(Question::getType, question.getType()));
        if (exists){
            //抛出异常
            throw new ExamException(444,"在<"+question.getType()+">分类下已存在该题目");
        }
        //1.调用mybatis-plus自带的方法保存题目,保存成功后questionId自动返回
        baseMapper.insert(question);
        //从题目表数据库获取自增的题目id
        Long questionId = question.getId();
        //获取题目对应的的答案对象
        QuestionAnswer answer = question.getAnswer();
        //将题目id设置到答案表里,设置外键约束,主表question从表answer,如果不是选择题答案添加问题的时候就添加了
        answer.setQuestionId(questionId);
        //判断是否是选择题,要从choices里找到正确的set进answer
        if ("CHOICE".equals(question.getType())){
            //获取所有选项
            List<QuestionChoice> choices = question.getChoices();
            //创建一个SpringBuild对象,用于拼接选项内容
            StringBuilder choiceContent = new StringBuilder();
            //遍历
            for (int i = 0; i < choices.size(); i++) {
                //获取每一个选项,想判断是否正确答案
                QuestionChoice questionChoice = choices.get(i);
                //为选项设置题目ID,选项表关联问题表,
                questionChoice.setQuestionId(questionId);
                //设置选项的排序
                questionChoice.setSort(i);
                //2.如果是选择题保存选项
                questionChoiceMapper.insert(questionChoice);
                //判断当前选项是否是正确答案
                if(questionChoice.getIsCorrect()){
                    if(choiceContent.length() > 0){
                        choiceContent.append(",");
                    }
                    choiceContent.append((char)('A'+i));
                }
            }
            //将正确答案设置到answer里
            answer.setAnswer(choiceContent.toString());
        }
        //将答案设置进答案表
        questionAnswerMapper.insert(answer);


    }

    @Override
    public Question getQuestionDetailsById(Long id) {
        //调用自定义的方法查答案详情
        Question question =  baseMapper.getQuestionDetailsById(id);
        //开启一个线程异步加载统计题目的访问次数
        new Thread(() ->{
            //向redis中添加当前题目的访问次数
            redisTemplate.opsForZSet().incrementScore("question:popular",id,1L);
        }).start();
        return question;
    }

    @Transactional
    @Override
    public void updateQuestion(Question question) {
        //判断前端传过来的更新后的题目是否在该类下已存在
        //创建LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //封装查询条件
        questionLambdaQueryWrapper
                .eq(Question::getType,question.getType())
                .eq(Question::getTitle,question.getTitle())
                .ne(Question::getId,question.getId());
        //调用QuestionMapper带条件查询的方法
        boolean exists = questionMapper.exists(questionLambdaQueryWrapper);
        //若存在抛异常
        if (exists){
            throw new ExamException(555,"在<"+question.getType()+">类下已存在改题目,请重新更新为其他题目");
        }
        //若不存在更新
        baseMapper.updateById(question);
        //从传来的question对象获取对应的答案对象
        QuestionAnswer answer = question.getAnswer();
        //判断是否是选择题
        if ("CHOICE".equals(question.getType())){
            //调用选项mapper逻辑删除原来所有选项.delete(new lqw<>().qc:getqid,q.getid) 只是逻辑删除,qc中id并未删除
            questionChoiceMapper.delete(new LambdaQueryWrapper<QuestionChoice>().eq(QuestionChoice::getQuestionId,question.getId()));
            //从传来的question获取所有选项q.getchoices()->choices
            List<QuestionChoice> choices = question.getChoices();
            //创建一个StringBuilder用以拼接答案
            StringBuilder choiceContent = new StringBuilder();
            //遍历choices
            for (int i = 0; i < choices.size(); i++) {
                //获取每一个选项
                QuestionChoice questionChoice = choices.get(i);
                //设置id为null,choice.setId(null)
                questionChoice.setId(null);
                //设置创建时间和更新时间为null
                questionChoice.setCreateTime(null);
                questionChoice.setUpdateTime(null);
                //设置选项排序
                questionChoice.setSort(i);
                //保存选择题的选项,只操作选项表插入,调用questionChoiceMapper的insert传(choice)这个选项对象
                questionChoiceMapper.insert(questionChoice);
                //判断是否是正确答案用sb的append拼接,字符串长度>0,再拼接要加,隔开用(char)类型拼A,B,C,D后面再
                if (questionChoice.getIsCorrect()) {
                    if (choiceContent.length()>0){
                        choiceContent.append(",");
                    }
                    choiceContent.append((char)('A'+i));
                }
            }
            //调answer对象的setAnswer方法把字符串.toString()设置到answer里
            answer.setAnswer(choiceContent.toString());
        }
        //更新题目答案
        questionAnswerMapper.updateById(answer);
    }

    @Transactional
    @Override
    public boolean deleteQuestionById(Long id) {
        //判断如果题目被谋试卷使用,不能删除
        Long count = paperQuestionMapper.selectCount(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getQuestionId, id));
        if (count > 0){
            //抛异常
            throw new ExamException(666,"当前题目已经被试卷使用,不能删除");
        }
        //根据id删除题目
        baseMapper.deleteById(id);
        //根据id删除题目答案
        questionAnswerMapper.delete(new LambdaQueryWrapper<QuestionAnswer>().eq(QuestionAnswer::getQuestionId,id));
        //根据id删除题目的选项
        questionChoiceMapper.delete(new LambdaQueryWrapper<QuestionChoice>().eq(QuestionChoice::getQuestionId,id));
        return true;
    }

    @Override
    public List<Question> getPopularQuestions(Integer size) {
        //定义热门题目总集合
        ArrayList<Question> popularQuestions = new ArrayList<>();
        //从Redis中获取热门题目ID
        Set<Object> redisQuestionIds = redisTemplate.opsForZSet().reverseRange("question:popular", 0, size - 1);
        //新建返回列表
        ArrayList<Question> returnList = new ArrayList<>();
        //判断如果redis里热门题目非空且非null,用id从数据库里取热门题目信息存到returnList里
        if(redisQuestionIds != null && redisQuestionIds.size() > 0){
            redisQuestionIds.forEach(questionId -> {
                //根据id查题目
                Question questionDetailsById = baseMapper.getQuestionDetailsById(Long.parseLong(questionId.toString()));
                //将题目添加到返回集合
                returnList.add(questionDetailsById);
            });
        }

        //获取redis中热门题目数量,如果不够要从题目表里拿最新创建的
        int redisSize = redisQuestionIds.size();
        int diff = size - redisSize;
        if (diff > 0){
            //拿diff个
            //创建lambdaquerywrapper对象,构建查询条件
            LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            //封装查询条件
            //根据创建时间降序
            questionLambdaQueryWrapper.orderByDesc(Question::getCreateTime);
            //排除redis里已取的
            questionLambdaQueryWrapper.notIn(redisQuestionIds.size()>0,Question::getId,redisQuestionIds);
            //在整个sql语句的最后拼接limit,拿几条数据
            questionLambdaQueryWrapper.last("limit "+diff);
            //执行带条件的查询
            List<Question> diffQuestions = baseMapper.selectList(questionLambdaQueryWrapper);
            returnList.addAll(diffQuestions);
        }


        return returnList;
    }
}